namespace SimpleWebServices.Models
{
    using System;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Web;
    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    using Newtonsoft.Json;
    using SimpleWebServices.Web;

    [JsonObject(MemberSerialization.OptIn)]
    [XmlRoot("site")]
    public sealed class Site : Resource, IXmlSerializable
    {
        public Site()
        {
            this.Assemblies = new Collection<string>();
            this.Cacheability = HttpCacheability.NoCache;
            this.Title = "Site Information";
        }

        public static Site Information
        {
            get
            {
                Collection<string> assemblies = new Collection<string>();
                foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().OrderBy(x => x.FullName))
                {
                    assemblies.Add(assembly.FullName);
                }

                return new Site
                {
                    Assemblies = assemblies,
                    Host = HttpContextFactory.Current.Request.Headers["Host"],
                    Machine = HttpContextFactory.Current.Server.MachineName
                };
            }
        }

        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Can't deserialize if the setter is private.")]
        [JsonProperty]
        [XmlArray("assemblies")]
        [XmlArrayItem("assembly")]
        public Collection<string> Assemblies
        {
            get;
            set;
        }

        [JsonProperty]
        [XmlAttribute("host")]
        public string Host
        {
            get;
            set;
        }

        [JsonProperty]
        [XmlAttribute("machine")]
        public string Machine
        {
            get;
            set;
        }

        public override string ToString()
        {
            StringBuilder buffer = new StringBuilder();
            buffer.AppendLine("[Server]");
            buffer.AppendLine("Host: " + this.Host);
            buffer.AppendLine("Machine: " + this.Machine);
            buffer.AppendLine(string.Empty);
            buffer.AppendLine("[Assemblies]");
            foreach (string assembly in this.Assemblies)
            {
                buffer.AppendLine("Assembly: " + assembly);
            }

            return buffer.ToString();
        }

        public XmlSchema GetSchema()
        {
            throw new NotSupportedException();
        }

        public void ReadXml(XmlReader reader)
        {
            if (null == reader)
            {
                throw new ArgumentNullException("reader");
            }

            this.Host = reader.GetAttribute("host");
            this.Machine = reader.GetAttribute("machine");

            if (reader.IsEmptyElement)
            {
                reader.Read();
            }
            else
            {
                string name = reader.Name;
                reader.Read();
                while (true)
                {
                    if (XmlNodeType.None == reader.NodeType)
                    {
                        break;
                    }
                    else if (XmlNodeType.EndElement == reader.NodeType && reader.Name == name)
                    {
                        reader.Read();
                        break;
                    }
                    else if (XmlNodeType.Element == reader.NodeType && reader.Name == "assembly")
                    {
                        this.Assemblies.Add(reader.ReadInnerXml());
                    }
                    else
                    {
                        reader.Read();
                    }
                }
            }
        }

        public void WriteXml(XmlWriter writer)
        {
            if (null == writer)
            {
                throw new ArgumentNullException("writer");
            }

            if (null != this.Host)
            {
                writer.WriteAttributeString("host", this.Host);
            }

            if (null != this.Machine)
            {
                writer.WriteAttributeString("machine", this.Machine);
            }

            writer.WriteStartElement("assemblies");
            foreach (string assembly in this.Assemblies)
            {
                writer.WriteElementString("assembly", assembly);
            }

            writer.WriteEndElement();
        }
    }
}